#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#include <string>
#include <cctype>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;


//将命令行参数表和相应的记录命令行参数个数的变量定义为全局
char* argv[100];
int argc;
char pwd[1024];
int exit_code = 0;//记录子进程的退出码

//检测重定向相关宏和变量
#define NONE_REDIR 0//无重定向
#define OUTPUT_REDIR 1//输出重定向
#define APPEND_REDIR 2//追加重定向
#define INPUT_REDIR 3//输入重定向
#define TRIMSPACE(start) while(isspace(*start)) start++;
string filename;
int redir_type = NONE_REDIR;

//#define DEBUG
#ifdef DEBUG

void Debug()
{
  cout << "hello linux" << endl; 
}


#endif 

string GetUser()
{
  return string(getenv("USER"));
}

string GetHost()
{
  return string(getenv("HOSTNAME"));
}

string GetPwd()
{
  //在第一次启动进程bash，并初始化加载环境变量表后，环境变量表不会自己自动更改，需要shell自行更新环境变量的值
  
  //使用getcwd获取当前进程的工作路径
  char tmp[1024];
  getcwd(tmp,sizeof(tmp));
  
  //putenv + snprintf
  snprintf(pwd,sizeof(pwd),"PWD=%s",tmp);
  putenv(pwd);

  // /home/wnf->简化更改路径
  string newPwd = tmp;
  size_t pos = newPwd.rfind("/");
  if(pos == string::npos)
  {
    return "NONE";
  }
  
  newPwd = newPwd.substr(pos + 1);

  return newPwd.empty()? "/" : newPwd;
}

string GetHomePath()
{
  return string(getenv("HOME"));
}


void PrintCommandPrompt()
{
  string user = GetUser();
  string host = GetHost();
  string pwd = GetPwd();
  printf("[%s@%s %s]# ",user.c_str(),host.c_str(),pwd.c_str());
  fflush(stdout);
}

bool GetCommandString(char str_buffer[],int buffer_size)
{
  if(str_buffer == nullptr || buffer_size <= 0)
    return false;
  char* res = fgets(str_buffer,buffer_size,stdin);
  if(res == nullptr)
    return false;

  //res这个字符串末尾还带有一个换行符，因此需要做相应处理
  str_buffer[strlen(res) - 1] = '\0';
 //cout << res << endl;
  return true;
}

void CheckRedir(char str_buffer[])
{
  char* st = str_buffer,*ed = st + strlen(str_buffer);
  redir_type = NONE_REDIR;
  while(st < ed)
  {
    if(*st == '>')
    {
      if(*(st + 1) == '>')
      {
        //追加重定向
        redir_type = APPEND_REDIR; 
        *st = '\0';
        st += 2;
      }
      else 
      {
        //输出重定向
        redir_type = OUTPUT_REDIR;
        *st = '\0';
        st++;
      }  
      TRIMSPACE(st);
      filename = st;
      break;
    }
    else if(*st == '<')
    {
      //输入重定向
      redir_type = INPUT_REDIR;
      *st = '\0';
      st++;
      TRIMSPACE(st);
      filename = st;
      break;
    }
    st++;
  }
}
bool ParseCommandString(char cmd[])
{
  if(cmd == nullptr)
    return false;
  argv[argc++] = strtok(cmd," "); 

  //即以空格为分隔符记录了命令行参数，同时使得命令行参数表以nullptr结尾
  while((bool)(argv[argc++] = strtok(nullptr," ")));
  argc--;



  //测试代码
  //#define DEBUG 
  #ifdef DEBUG 
    printf("argc:%d\n",argc);
    printf("----------------------\n");
    for(int i = 0;i < argc;i++)
    {
      printf("argv[%d]:%s\n",i,argv[i]);
    }
    printf("----------------------\n");
    for(int i = 0;argv[i];i++)
    {
      printf("argv[%d]:%s\n",i,argv[i]);
    }
  #endif 
    return true;
}

void GlobalInit()
{
  argc = 0;
  memset(argv,0,sizeof(argv));
}

void ForkAndExec()
{
  pid_t id = fork();
  if(id < 0)
  {
    perror("fork");
    return;
  }
  else if(id == 0)
  {
    if(redir_type == INPUT_REDIR)
    {
      int fd = open(filename.c_str(),O_RDONLY); 
      dup2(fd,0);
    }
    else if(redir_type == OUTPUT_REDIR)
    {
      int fd = open(filename.c_str(),O_WRONLY | O_CREAT | O_TRUNC,0666);
      dup2(fd,1);
    }
    else if(redir_type == APPEND_REDIR)
    {
      int fd = open(filename.c_str(),O_WRONLY | O_CREAT | O_APPEND,0666);
      dup2(fd,1);
    }
    //子进程
    execvp(argv[0],argv);//进程替换
    exit(0);//正常退出
  }
  else 
  {
    //父进程
    //父进程要回收子进程
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    if(rid < 0)
    {
      perror("waitpid");
      return;
    }
    else 
    {
      exit_code = WEXITSTATUS(status);
    }
  }
}

bool BuiltInCommand()
{
  string cmd = argv[0];
  bool ret = false;  
  //1.内建命令cd
  if(cmd == "cd")
  {
    ret = true;
    if(argc >= 2)
    {
      string target = argv[1];
      if(target == "~")
      {
        chdir(GetHomePath().c_str());
      }
      else 
      {
        chdir(argv[1]);
      }
    }
    else 
    {
      //直接cd，返回家目录
      chdir(GetHomePath().c_str());
    }
  }
  else if(cmd == "echo")
  {
    ret = true;
    if(argc >= 2)
    {
      string args = argv[1];
      if(args[0] == '$' && args.size() >= 2)
      {
        if(args[1] == '?')
        {
          printf("exit_code:%d\n",exit_code);
        }
        else 
        {
          printf("%s\n",getenv(&args[1]));
        }
      }
      else 
      {
         printf("%s\n",args.c_str());
      }
    }
  }
  if(ret)
    exit_code = 0;
  return ret;
}


